package nl.boelen.game.entities;

import java.util.Random;

import nl.boelen.game.client.Client;
import nl.boelen.game.entities.functions.Health;
import nl.boelen.game.entities.functions.Inventory;
import nl.boelen.game.gfx.Colors;
import nl.boelen.game.gfx.Screen;
import nl.boelen.game.handler.KeyboardHandler;
import nl.boelen.game.level.tile.Tile;
import nl.boelen.game.net.packet.Packet31Movement;
import nl.boelen.game.options.Option;

public class Player extends Mob {

    private String uniqueKey;
    private String userName;

    private int animationPauseLength = Option.ANIMATIONRESET;
    private int tickCount = new Random().nextInt(15);
    private int walkAnimationCounter = 0;
    private int scale = 1;
    private int modifier;
    private int sendCount;
    private int shirtColor;
    private int skinColor;
    private int sendX;
    private int sendY;
    private int moveX;
    private int moveY;
    private int xOffset;
    private int yOffset;

    private int lavaResistance = 0;
    private int fireResistance = 0;

    protected boolean isMouseHover = false;
    protected boolean showAttributes = true;
    protected boolean didCount = false;
    protected boolean hasAnimation = false;
    protected boolean isSwimming = false;
    protected boolean inLava = false;
    protected boolean onFire = false;
    protected boolean isClient = false;
    protected boolean mustDecreaseY = false;
    protected boolean mustIncreaseY = false;
    protected boolean mustDecreaseX = false;
    protected boolean mustIncreaseX = false;

    private Health health;
    private Inventory inventory;
    private KeyboardHandler keyboard;

    public Player(final Client client, int x, int y, KeyboardHandler keyboard, String userName, String uniqueKey, int shirtColor, int maxhp) {
        super(client, "Player", x, y, 1);
        this.keyboard = keyboard;
        this.userName = userName;
        this.uniqueKey = uniqueKey;
        this.shirtColor = shirtColor;

        if (keyboard != null) {
            this.isClient = true;
        }
        this.health = new Health(maxhp, isClient, client, this);
        this.inventory = new Inventory(client, this);
    }

    @Override
    public boolean hasCollided(int xa, int ya) {
        int xMin = 0;
        int xMax = 7;
        int yMin = 3;
        int yMax = 7;

        for (int x = xMin; x < xMax; x++) {
            if (isSolidTile(xa, ya, x, yMin) || isSolidTile(xa, ya, x, yMax)) {
                return true;
            }
        }

        for (int y = yMin; y < yMax; y++) {
            if (isSolidTile(xa, ya, xMin, y) || isSolidTile(xa, ya, xMax, y)) {
                return true;
            }
        }

        return false;
    }

    private void checkMovement() {
        boolean checkMovement = false;
        if (isSwimming) {
            if (tickCount % 2 == 0) {
                checkMovement = true;
            }
        } else {
            checkMovement = true;
        }
        if (checkMovement) {
            if (keyboard.up.isPressed()) {
                moveY--;
            }
            if (keyboard.down.isPressed()) {
                moveY++;
            }
            if (keyboard.left.isPressed()) {
                moveX--;
            }
            if (keyboard.right.isPressed()) {
                moveX++;
            }
        }
        sendCount++;
        if (sendCount % 6 == 0) {
            if (this.x != sendX || this.y != sendY || sendMovingDirection != movingDirection) {
                Packet31Movement packet = new Packet31Movement(this.getUniqueKey(), this.x, this.y, this.movingDirection);
                client.UDP.sendPacket(packet);
                sendX = this.x;
                sendY = this.y;
                sendMovingDirection = this.movingDirection;
            }
        }
    }

    private void checkActions() {
        if (keyboard.x.isPressed()) {
            System.out.println("x = pressed");
        }
    }

    public String getUserName() {
        return userName;
    }

    public String getUniqueKey() {
        return uniqueKey;
    }

    public int getShirtColor() {
        return shirtColor;
    }

    public int getScale() {
        return scale;
    }

    public boolean isSwimming() {
        return isSwimming;
    }

    @Override
    public void tick() {
        moveX = 0;
        moveY = 0;
        if (isClient) {
            checkMovement();
            checkActions();
        } else {
            if (mustDecreaseY) {
                moveY--;
                mustDecreaseY = false;
            }
            if (mustIncreaseY) {
                moveY++;
                mustIncreaseY = false;
            }
            if (mustDecreaseX) {
                moveX--;
                mustDecreaseX = false;
            }
            if (mustIncreaseX) {
                moveX++;
                mustIncreaseX = false;
            }
        }

        if (moveX != 0 || moveY != 0) {
            isMoving = true;
            animationPauseLength = Option.ANIMATIONRESET;
            move(moveX, moveY);
        } else {
            isMoving = false;
        }

        switch (client.level.getTile((this.x + 4) >> 3, (this.y + 4) >> 3).getId()) {
            case Tile.WATERID:
                isSwimming = true;
                onFire = false;
                break;
            case Tile.LAVAID:
                isSwimming = true;
                inLava = true;
                onFire = true;
                if (tickCount % (5 + lavaResistance) == 0) {
                    health.valueHit(2);
                }
                break;
            default:
                isSwimming = false;
                inLava = false;
                break;
        }

        if (!onFire) {
            if (tickCount % 10 == 0) {
                health.addValue(1);
            }
        } else if (!inLava) {
            if (tickCount % (15 + fireResistance) == 0) {
                health.valueHit(1);
            }
        }

        tickCount++;
    }

    private void renderBody(Screen screen) {
        int xTile = 0;
        int yTile = 27;

        int walkingSpeed = 3;

        int flipTop = (numSteps >> walkingSpeed) & 1;
        int flipBottom = (numSteps >> walkingSpeed) & 1;

        if (animationPauseLength > 0) {
            hasAnimation = true;
            animationPauseLength--;
        } else {
            hasAnimation = false;
        }

        if (movingDirection == Option.UP) {
            if (isMoving || hasAnimation) {
                xTile += 2;
            }
        } else if (movingDirection == Option.DOWN) {
            xTile += 4;
            if (isMoving || hasAnimation) {
                xTile += 2;
            }
        } else if (movingDirection == Option.LEFT || movingDirection == Option.RIGHT) {
            xTile += 8;
            if (isMoving || hasAnimation) {
                if (((numSteps >> walkingSpeed) % 2) != 0) {
                    didCount = false;
                    if ((walkAnimationCounter % 2) == 0) {
                        xTile += 2;
                    } else {
                        xTile += 4;
                    }
                } else {
                    if (!didCount) {
                        didCount = true;
                        walkAnimationCounter++;
                    }
                }
            }
            flipTop = (movingDirection - 1) % 2;
            flipBottom = (movingDirection - 1) % 2;
        }

        // TOP BODY
        screen.render(xOffset + (modifier * flipTop), yOffset, xTile + yTile * 32, skinColor, flipTop, scale);
        screen.render(xOffset + modifier - (modifier * flipTop), yOffset, (xTile + 1) + yTile * 32, skinColor, flipTop, scale);

        if (!inLava && !isSwimming) {
            // LOWER BODY
            screen.render(xOffset + (modifier * flipBottom), yOffset + modifier, xTile + (yTile + 1) * 32, skinColor, flipBottom, scale);
            screen.render(xOffset + modifier - (modifier * flipBottom), yOffset + modifier, (xTile + 1) + (yTile + 1) * 32, skinColor,
                    flipBottom, scale);
        }

    }

    private void renderPhisics(Screen screen) {
        if (inLava) {
            yOffset += 5;
            skinColor = Colors.get(-1, 101, 500, 522);
            if (tickCount % 20 < 5) {
                yOffset -= 1;
            } else if (tickCount % 20 < 10) {
                yOffset -= 2;
            } else if (tickCount % 20 < 15) {
                yOffset -= 1;
            }
        } else if (isSwimming) {
            int waterColor = 0;
            yOffset += 4;
            if (tickCount % 60 < 15) {
                waterColor = Colors.get(-1, -1, 225, -1);
                yOffset -= 1;
            } else if (15 <= tickCount % 60 && tickCount % 60 < 30) {
                waterColor = Colors.get(-1, 225, 115, -1);
            } else if (30 <= tickCount % 60 && tickCount % 60 < 45) {
                waterColor = Colors.get(-1, 115, -1, 225);
            } else {
                waterColor = Colors.get(-1, 225, 115, -1);
            }

            // SWIMMING ANIMATION
            screen.render(xOffset, yOffset + (3 * scale), (0 + 26 * 32), waterColor, 0x00, scale);
            screen.render(xOffset + 8 * scale, yOffset + (3 * scale), (0 + 26 * 32), waterColor, 0x01, scale);
        }

        if (onFire) {
            int fireColor = 0;
            if (tickCount % 60 < 15) {
                skinColor = Colors.get(-1, 101, 500, 522);
                fireColor = Colors.get(-1, 500, -1, -1);
            } else if (15 <= tickCount % 60 && tickCount % 60 < 30) {
                skinColor = Colors.get(-1, 101, 510, 522);
                fireColor = Colors.get(-1, 531, 500, -1);
            } else if (30 <= tickCount % 60 && tickCount % 60 < 40) {
                skinColor = Colors.get(-1, 101, 500, 522);
                fireColor = Colors.get(-1, 540, 531, 500);
            } else if (40 <= tickCount % 60 && tickCount % 60 < 50) {
                skinColor = Colors.get(-1, 101, 500, 522);
                fireColor = Colors.get(-1, 531, 531, 540);
                if (!inLava) {
                    yOffset += 1;
                }
            } else {
                skinColor = Colors.get(-1, 101, 500, 511);
                fireColor = Colors.get(-1, 540, 531, 500);
            }

            // FIRE ANIMATION HEAD
            screen.render(xOffset, yOffset - 8 + (3 * scale), (1 + 26 * 32), fireColor, 0x00, scale);
            screen.render(xOffset + 8 * scale, yOffset - 8 + (3 * scale), (1 + 26 * 32), fireColor, 0x01, scale);

            // FIRE ANIMATION ARMS
            if (movingDirection != Option.LEFT && movingDirection != Option.RIGHT && !isSwimming) {
                screen.render(xOffset - 2, yOffset - 2 + (3 * scale), (1 + 26 * 32), fireColor, 0x00, scale);
                screen.render(xOffset + 8 * scale + 2, yOffset - 2 + (3 * scale), (1 + 26 * 32), fireColor, 0x01, scale);
            }
        }
    }

    private void renderHealth() {
        int xHealth = xOffset + 3;
        int yHealth = yOffset + 17;

        if (isSwimming) {
            yHealth -= 2;
        }

        health.renderHealth(xHealth, yHealth, scale * 10);
    }

    private void renderInventory() {
        inventory.render();
    }

    private void renderName() {
        if (userName != null) {
            if (isClient) {
                client.font.render(userName, Option.ClientWIDTH + client.screen.xOffset - (userName.length() << 3), Option.ClientHEIGHT
                        + client.screen.yOffset - 8, Colors.get(0, -1, -1, 555), 1);
            } else if(client.playerHovered == this){
                client.font.render(userName, xOffset - ((userName.length() << 2) - 8), yOffset - 10, Colors.get(-1, -1, -1, 555), 1);
                // draw a border around the player
                for (int w = 0; w < 16; w++) {
                    for (int h = 0; h < 16; h++) {
                        if (w == 0 && h <= 2 || w == 0 && h >= 13 || h == 0 && w <= 2 || h == 0 && w >= 13 || w == 15 && h <= 2 || w == 15
                                && h >= 13 || h == 15 && w <= 2 || h == 15 && w >= 13) {
                            client.screen.pixels[xOffset + w + (yOffset + h) * client.screen.width] = Colors.get(550);
                        }
                    }
                }
            }
        }
    }

    private void checkHoverMouse() {
        int xPos = xOffset;
        int yPos = isSwimming ? yOffset + 4 : yOffset;
        if (client.mouse.getMouseX() >= xPos - client.screen.xOffset && client.mouse.getMouseX() <= xPos - client.screen.xOffset + 16) {
            if (client.mouse.getMouseY() >= yPos - client.screen.yOffset && client.mouse.getMouseY() <= yPos - client.screen.yOffset + 16) {
                if(client.playerHovered == null){
                    isMouseHover = true;
                    client.playerHovered = this;
                }
                return;
            }
        }
        isMouseHover = false;
    }

    @Override
    public void render(Screen screen) {
        modifier = 8 * scale;
        xOffset = x - modifier / 2;
        yOffset = y - modifier / 2 - 4;
        skinColor = Colors.get(-1, 111, shirtColor, 543);

        checkHoverMouse();
        renderPhisics(screen);
        renderBody(screen);
        if (isMouseHover) {
            renderName();
        }

        if (isClient) {
            health.renderHealthBarClient(0, screen.height - 1, 56, 2);
            renderInventory();
        } else {
            renderHealth();
        }
    }

    public Health getHealthObject() {
        return health;
    }
}